]> dgit.raspbian.org Git - gnome-shell.git/commitdiff
status/keyboard: Synchronize input source switching with key events
authorRui Matos <tiagomatos@gmail.com>
Wed, 27 Mar 2013 00:01:33 +0000 (01:01 +0100)
committerRui Matos <tiagomatos@gmail.com>
Mon, 27 May 2013 12:05:50 +0000 (14:05 +0200)
Currently we simply set the gsettings key when activating an input
source. This obviously introduces a time window, between the event that
activates the switch and when the switch is complete, under which key
events are being delivered to applications and interpreted according
to the previous input source.

The patches in bug 696996 introduce a DBus API in g-s-d that allows us
to know when an input source if effectively active. Using that and
freezing keyboard events in the X server until we hear back from g-s-d
we can ensure that events won't be misinterpreted after an input
source switch.

https://bugzilla.gnome.org/show_bug.cgi?id=697007

js/ui/status/keyboard.js
src/shell-global.c
src/shell-global.h

index 4880fd2bb123b5196e633ea43c3b3a7ec956842c..0dbcc4ac4645d19df60692604cfc2cb59fb62d4f 100644 (file)
@@ -33,6 +33,33 @@ const KEY_INPUT_SOURCES = 'sources';
 const INPUT_SOURCE_TYPE_XKB = 'xkb';
 const INPUT_SOURCE_TYPE_IBUS = 'ibus';
 
+// This is the longest we'll keep the keyboard frozen until an input
+// source is active.
+const MAX_INPUT_SOURCE_ACTIVATION_TIME = 4000; // ms
+
+const BUS_NAME = 'org.gnome.SettingsDaemon.Keyboard';
+const OBJECT_PATH = '/org/gnome/SettingsDaemon/Keyboard';
+
+const KeyboardManagerInterface =
+<interface name="org.gnome.SettingsDaemon.Keyboard">
+<method name="SetInputSource">
+    <arg type="u" direction="in" />
+</method>
+</interface>;
+
+const KeyboardManagerProxy = Gio.DBusProxy.makeProxyWrapper(KeyboardManagerInterface);
+
+function releaseKeyboard() {
+    if (Main.modalCount > 0)
+        global.display.unfreeze_keyboard(global.get_current_time());
+    else
+        global.display.ungrab_keyboard(global.get_current_time());
+}
+
+function holdKeyboard() {
+    global.freeze_keyboard(global.get_current_time());
+}
+
 const IBusManager = new Lang.Class({
     Name: 'IBusManager',
 
@@ -364,6 +391,13 @@ const InputSourceIndicator = new Lang.Class({
         this._ibusManager.connect('property-updated', Lang.bind(this, this._ibusPropertyUpdated));
         this._inputSourcesChanged();
 
+        this._keyboardManager = new KeyboardManagerProxy(Gio.DBus.session, BUS_NAME, OBJECT_PATH,
+                                                         function(proxy, error) {
+                                                             if (error)
+                                                                 log(error.message);
+                                                         });
+        this._keyboardManager.g_default_timeout = MAX_INPUT_SOURCE_ACTIVATION_TIME;
+
         this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
         this._showLayoutItem = this.menu.addAction(_("Show Keyboard Layout"), Lang.bind(this, this._showLayout));
 
@@ -488,10 +522,8 @@ const InputSourceIndicator = new Lang.Class({
             let is = new InputSource(type, id, displayName, shortName, i);
 
             is.connect('activate', Lang.bind(this, function() {
-                if (this._currentSource && this._currentSource.index == is.index)
-                    return;
-                this._settings.set_value(KEY_CURRENT_INPUT_SOURCE,
-                                         GLib.Variant.new_uint32(is.index));
+                holdKeyboard();
+                this._keyboardManager.SetInputSourceRemote(is.index, releaseKeyboard);
             }));
 
             if (!(is.shortName in inputSourcesByShortName))
index da7732bf983aa1b7716679703455ed677940fe28..4a82b953322d134874951a9d371d038334c80684 100644 (file)
@@ -1007,6 +1007,13 @@ shell_global_end_modal (ShellGlobal *global,
   meta_plugin_end_modal (global->plugin, timestamp);
 }
 
+void
+shell_global_freeze_keyboard (ShellGlobal *global,
+                              guint32      timestamp)
+{
+  meta_display_freeze_keyboard (global->meta_display, global->stage_xwindow, timestamp);
+}
+
 /* Code to close all file descriptors before we exec; copied from gspawn.c in GLib.
  *
  * Authors: Padraig O'Briain, Matthias Clasen, Lennart Poettering
index 38532b5eec507a8d45e551061e4fd5f1f44b0958..c93cb1bdfc42b83fd8e22b344dcc5adfbceffd0e 100644 (file)
@@ -44,6 +44,8 @@ gboolean shell_global_begin_modal            (ShellGlobal         *global,
                                               MetaModalOptions    options);
 void     shell_global_end_modal              (ShellGlobal         *global,
                                               guint32              timestamp);
+void     shell_global_freeze_keyboard        (ShellGlobal         *global,
+                                              guint32              timestamp);
 
 typedef enum {
   SHELL_STAGE_INPUT_MODE_NORMAL,